home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 22 / Cream of the Crop 22.iso / program / ctlib100.zip / INSTALL.LZH / SEQUENCE.TXT < prev    next >
Text File  |  1996-10-12  |  12KB  |  224 lines

  1.                           CHAPTER 3
  2.                       Linear containers
  3.  
  4.  
  5. This chapter describes the complete interface of TSequence, the base object for all linear containers in the Containers Library object hierarchy.  All linear containers are ultimately derived from TSequence, so the topics discussed in this chapter apply to all linear containers in the library.
  6.  
  7. In this chapter you will learn how to:
  8.  
  9.   - Use the At methods to insert, replace and delete data
  10.     using index values
  11.   - Move through the items in a linear container
  12.   - Use iterative methods for finding items and conditionally
  13.     moving through a linear container
  14.  
  15.  
  16. Using the At methods
  17.  
  18. Linear containers provide a set of At methods that allow you to access data items by using their index values.  At methods let you retrieve, insert, replace and delete data at specific positions in a container.
  19.  
  20.  
  21. Retrieving data using At
  22.  
  23. You can easily retrieve a particular data item from a container by using the At method.  At takes one parameter, which is the index of the item that you want to retrieve, and returns a pointer to the data item in the container.  The following statement, for example, retrieves the item stored at the 15th position in an array:
  24.  
  25.   Item := MyArray^.At(15);
  26.  
  27. At can also be used within loops to visit all items in a container:
  28.  
  29.   with MyTable^ do
  30.     for i := 0 to Pred(Count) do
  31.       Inc(PMyObject(At(i))^.DaysWorked);
  32.  
  33. The range of index values assigned to items in a container is defined by the value of the FirstIndex field.  By default, FirstIndex is 0.  However, If you want to change the range of index values used by a container, all you have to do is set FirstIndex to the first valid index in the new range of values you want to use.
  34.  
  35.   MyList := New(PList, Init);
  36.   MyList^.FirstIndex := 15;
  37.  
  38.   { get first index in the list }
  39.   Item := MyList^.At(15);
  40.  
  41.   { The following statement will }
  42.   { cause an out of range error. }
  43.   Item := MyList^.At(0);
  44.  
  45. Warning!  FirstIndex must have a value of at least Succ(MinLongInt).  Otherwise, methods in the container will not work correctly.
  46.  
  47.  
  48. Adding data using AtInsert
  49.  
  50. In linear containers, you can insert data at specific positions by using the AtInsert method.  Just like the standard Insert method, AtInsert takes as a parameter a pointer to the data item that you want to insert into the container.  However, when using AtInsert, you must also provide the index where you want to insert the item.
  51.  
  52.   MyList^.AtInsert(Item, 15);
  53.  
  54. Before inserting the data item, the container will move all items at position index or higher in the container up by one position.  In our example above, the item at position 15 will be moved to position 16, the one at position 16 will be moved to position 17, and so on until all items have been relocated. The new item is then inserted at position 15.  If the container is full, dynamically sized containers will automatically increase their size to allocate space for the new item.  Statically sized containers, however, will usually just delete the last item in the container, before attempting to insert the new item.  Statically sized containers include some of the standard array containers.
  55.  
  56.  
  57. Replacing data
  58.  
  59. Sometimes, you might want to place an item at a particular position in a sequence (or replace an existing item at that position) but do not want other items to be affected as a result of the new insertion.  AtPut and AtReplace let you do exactly this.  These methods take two parameters:  the index of the item that you want to replace and a pointer to the new item that you want to insert instead.  AtPut replaces the item at the Index'th position in the container with the new item, but does not dispose of the item being replaced.  For example,
  60.  
  61.   Item := MyStreamArray^.At(15);
  62.   Inc(PMyObject(Item)^.PointsEarned);
  63.   MyStreamArray^.AtPut(15, Item);
  64.  
  65. If you want to also dispose of the old item, you must use AtReplace instead.
  66.  
  67.   Item := NewItem;
  68.   PMyObject(Item)^.Key := NewKey;
  69.   MyHugeCollection^.AtReplace(6, Item);
  70.  
  71. In this example, the last statement causes the huge collection container to delete and dispose of whatever item is stored at position 6.  After the old item has been properly disposed of, the new item is inserted.
  72.  
  73. Warning!  You must be careful not to use AtReplace when you simply want to update a data item (as in the first example).  Otherwise, the container will dispose of the item that you want to update and then try to insert the item it just disposed of, which will cause a general protection fault error in protected mode applications or cause real mode applications to become unstable.
  74.  
  75.  
  76. Deleting data
  77.  
  78. Finally, you can also use At methods to delete items at specific positions in a container.  TSequence provides the AtDelete and AtFree methods for this purpose.  Both methods take only one parameter, which is the index position of the item that you want to delete.  
  79.  
  80. AtDelete does not dispose of the item deleted, so it is important that you call FreeItem to dispose of the item after you are done using it.  For example,
  81.  
  82.   with MyCollection^ do
  83.   begin
  84.     Item := At(16);
  85.     AtDelete(16);
  86.     {... do something with Item ...}  
  87.     FreeItem(Item);  { dispose of Item }
  88.   end;
  89.  
  90. If you need to both delete and dispose of an item, you must use AtFree instead.  AtFree is equivalent to:
  91.  
  92.   Item := At(Index);
  93.   AtDelete(Index);
  94.   FreeItem(Item);
  95.  
  96.  
  97. Moving in a linear container
  98.  
  99. TSequence implements a series of methods that will allow you to move through the items in a container, one item at a time.  These include First, Next, Last and Prev.  You can use this methods whenever you want to move in a container in any direction one item at a time, or as an alternative to iterative methods that will give you more control over each iteration.
  100.  
  101.  
  102. First
  103.  
  104. This method returns the first item stored in a linear container.  Note that this is not necessarily the first item that you inserted.
  105.  
  106.   Item := MySequence^.First(Index);
  107.  
  108. First takes one parameter, Index, in which it stores the index of the item returned.  This value will always be equal to FirstIndex, but is provided by First anyway to be used as a seed value (or starting point) for other methods like Next or Prev.  Usually, you will use First together with Next or Prev to move through the items in a container.
  109.  
  110.  
  111. Next
  112.  
  113. Next takes one parameter, Index, and returns the next item following the item at the index'th position.  The index of the item returned is stored in Index so that it can be used as a seed value (or starting point) in other methods (e.g., Prev) or in another call to Next.
  114.  
  115.   with MySequence^ do
  116.   begin
  117.     if Status > ctOk { reset Status }
  118.       then Status := ctOk; 
  119.     Item := First(Index);
  120.     while Status = ctOk do
  121.     begin
  122.       {... do something with Item ...}
  123.       Item := Next(Index);
  124.     end;
  125.   end;
  126.  
  127.  
  128. Last
  129.  
  130. This method returns the last item stored in a linear container.  Note that this is not necessarily the last item that you inserted.
  131.  
  132.   Item := MySequence^.Last(Index);
  133.  
  134. Last takes one parameter, Index, in which it stores the index of the item returned.  This value will always be equal to Pred(FirstIndex + Count), but is provided by Last anyway to be used as a seed value (or starting point) for other methods like Prev or Next.  Usually, you will use Last together with Prev or Next to move through the items in a container.
  135.  
  136.  
  137. Prev
  138.  
  139. Prev takes one parameter, Index, and returns the item preceding the item at the index'th position.  The index of the item returned is stored in Index so that it can be used as a seed value (or starting point) in other methods (e.g., Next) or in another call to Prev.
  140.  
  141.   with MySequence^ do
  142.   begin
  143.     if Status > ctOk { reset Status }
  144.       then Status := ctOk; 
  145.     Item := Last(Index);
  146.     while Status = ctOk do
  147.     begin
  148.       {... do something with Item ...}
  149.       Item := Prev(Index);
  150.     end;
  151.   end;
  152.  
  153.  
  154. Seed values
  155.  
  156. A seed value is a value used as a starting point of an operation.  In the case of methods in a container, a seed value is the point where the container will start new searches for a data item.  
  157.  
  158. In containers, seed values allows you to have different views of the data at the same time.  For example, by using seed values, you can use a data-control to browse the first 20 records in a data set while at the same time use a different data-control to modify the last 20 records in the same data set.  As a result, however, containers cannot keep track of their "current" position (i.e. they do not use the last item accessed as the starting point for other methods).  Therefore, if you need to know which was the last item you accessed, you need to store the seed values returned by container methods.  Alternatively, you can use a cursor object that will keep track of your position in the container for you.
  159.  
  160.  
  161. Iterative methods
  162.  
  163. Additional iterative methods in TSequence allow you to quickly find any item in a linear container or conditionally move through all the items stored in it.  These methods work just like First, Next, Prev and Last, but allow you to filter the items that are actually visited in a search.
  164.  
  165.  
  166. The FirstThat and LastThat iterators
  167.  
  168. FirstThat and LastThat iterators provide an easy way of finding items in a container.  FirstThat returns the first item in a container that satisfies a search criterion while LastThat returns the last item in a container that satisfies a search criterion.
  169.  
  170. These iterators take two parameters:  a pointer to a far local boolean function of type TTestFunction and an integer variable parameter where the index of the item returned will be stored.  This value can be used as a seed value (or starting point) in other methods like NextThat or PrevThat.
  171.  
  172.   procedure FindWinners;
  173.  
  174.     function IsWinner(Item : PMyObject): Boolean; far;
  175.     begin
  176.       IsWinner := Item^.LotteryNumber := '2736491';
  177.     end;
  178.  
  179.   begin
  180.     with MySequence^ do
  181.     begin
  182.       if Status > ctOk
  183.         then Status := ctOk;
  184.       Item := FirstThat(@IsWinner, Index);
  185.       while Status = ctOk do
  186.       begin
  187.         DisplayWinner(Item);
  188.         Item := NextThat(@IsWinner, Index);
  189.       end; 
  190.     end;
  191.   end;
  192.  
  193. Remember to be careful about what sort of functions you call with these iterators.  Remember that the functions cannot be an object's methods and that it must be local to (nested in the same block with) the routine that is calling it.  Functions must also be declared as far functions, either with the far directive or with the $F+ compiler directive.  Finally, the functions must take a pointer to a container item as their only parameter.
  194.  
  195.  
  196. The NextThat and PrevThat iterators
  197.  
  198. When used together with FirstThat and LastThat, the NextThat and PrevThat iterators provide a way of conditionally moving through a container.  That is, the let you select or filter the items that you want to visit when moving in a container.
  199.  
  200. These iterators take two parameters:  a pointer to a far local boolean function of type TTestFunction and the index in the container where you want to start the search.  The index of the item returned is stored in this parameter, and it can then be used as a seed value (or starting point) in other calls to NextThat and PrevThat.
  201.  
  202.   procedure DisplayReversePrimes;
  203.  
  204.     function IsPrime(Item : PMyObject) : Boolean; far;
  205.     begin
  206.       IsPrime := NumberIsPrime(Item^.Value);
  207.     end;
  208.  
  209.   begin
  210.     with MySequence^ do
  211.     begin
  212.       if Status > ctOk
  213.         then Status := ctOk;
  214.       Item := LastThat(@IsPrime, Index);
  215.       while Status = ctOk do
  216.       begin
  217.         Display(Item);
  218.         Item := PrevThat(@IsPrime, Index);
  219.       end;
  220.     end;
  221.   end;
  222.  
  223. The first call to either NextThat or PrevThat should always be preceded by a call to First, FirstThat, Last or LastThat. The function of these methods is to set the starting point of new searches, though this is not necessary if you already know the index of the item where you want to begin your search.
  224.